#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/types.h>
#include<wait.h>


#define NUM 1024
#define SEP " "
#define SIZE 64


char cwd[1024];
char enval[1024]; // for test
int lastcode = 0;

//#define debug -1

// 获取环境变量 user,hostname,pwd
char *homepath()
{
    char *home= getenv("HOME");
    if(home) return home;
    else return (char*)".";
}

const char *getUsername()
{
    const char *name = getenv("USER");
    if(name) return name;
    else return "none";
}

const char *getHostname()
{

    const char *hostname = getenv("HOSTNAME");
    if(hostname) return hostname;
    else return "none";
}

const char *getCwd()
{
    const char *cwd = getenv("PWD");
    if(cwd) return cwd;
    else return "none";
}

int getUserCommand(char *command, int num)
{

    printf("[%s@%s %s]$ ",getUsername(), getHostname(), getCwd());
    char *r = fgets(command, num, stdin); // 最后还是会输入'\n'，回车
    if(r == NULL) return -1; // TODO
    command[strlen(command)-1] = '\0'; // 这里不会越界
    return strlen(command);
}
    
void commandSplit(char *in, char *out[])
{
   int argc = 0;
   out[argc++] = strtok(in, SEP);
   while(out[argc++] = strtok(NULL, SEP));

#ifdef debug
   int i = 0;
   for(i = 0; out[i]; i++)
   {
       printf("%d:%s\n", i, out[i]);
   } 
#endif
}

int execute(char *argv[])
{
    pid_t id = fork();
    if(id < 0) return -1;
    else if(id == 0)
    {
        // 子进程
        execvp(argv[0], argv);
        exit(1);
    }
    else{
        // 父进程
        int status = 0;

        pid_t rid = waitpid(id, &status, 0);
        if(rid > 0)
        {
            lastcode = WEXITSTATUS(status);
        }
    }
    return 0;
}

void cd(const char *pash)
{
    chdir(pash);
    char tmp[1024];
    getcwd(tmp, sizeof(tmp));
    sprintf(cwd, "PWD=%s", tmp);
    putenv(cwd);
}

int doBuildin(char *argv[])
{
    if(strcmp(argv[0], "cd") == 0)
    {
        char *pash = NULL;
        if(argv[1] == NULL) pash = homepath();
        else
        {
            pash = argv[1];
        }
        cd(pash);
        return 1;
    }

    else if(strcmp(argv[0], "exprot") == 0)
    {
        if(argv[1] == NULL) return 1;

        strcpy(enval, argv[1]);
        putenv(enval);
        return 1;
    }

    else if(strcmp(argv[0], "echo") == 0)
    {
        if(argv[1] == NULL)
        {
            printf("\n");
            return 1;
        }
        
        if(*(argv[1]) == '$' && strlen(argv[1]) > 1)
        {
            char *val = argv[1]+1;
            if(strcmp(val, "?") == 0)
            {
                printf("%d\n", lastcode);
                lastcode = 0;
            }
            else
            {
                const char *enval = getenv(val);
                if(enval) printf("%s\n", enval);
                else printf("\n");
            }
            return 1;
        }
        else{
            printf("%s\n",argv[1]);
            return 1;
        }
    }
    return 0;
}

int main()
{
    while(1)
    {
        char usercommand[NUM];
        char *argv[SIZE];
        // 获取输入
        int n = getUserCommand(usercommand, sizeof(usercommand));
        if(n <= 0) continue;
        // 分割字符串 (strtok)
        commandSplit(usercommand, argv);
        // check Buildin
        n = doBuildin(argv);
        if(n) continue;
        // 执行命令
        execute(argv);

    }   
    return 0;
}
